﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Eqwww.Domain.Models;
using Eqwww.Domain.Models.Identity;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using System.Reflection;
using Eqwww.Domain;
using Eqwww.Code;
using Eqwww.Domain.Models.SystemManage;
using Eqwww.Domain.Models.QuartzJob;
using Eqwww.Domain.Models.SystemSecurity;

namespace Eqwww.Data
{
    public class ApplicationDbContext : IdentityDbContext<UserModel, RoleModel, string>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }

        public DbSet<DbBackupModel> Sys_DbBackups { get; set; }

        public DbSet<OrganizeModel> Sys_Organizes { get; set; }
        public DbSet<PostModel> Sys_Posts { get; set; }
        public DbSet<JobModel> Sys_Jobs { get; set; }
        public DbSet<ModuleModel> Sys_Modules { get; set; }
        public DbSet<ModuleButtonModel> Sys_ModuleButtons { get; set; }
        public DbSet<ModuleClaimModel> Sys_ModuleClaims { get; set; }
        public DbSet<ModuleButtonClaimModel> Sys_ModuleButtonClaims { get; set; }

        public DbSet<DatabaseLogModel> Sys_DatabaseLogs { get; set; }
        public DbSet<UserPostModel> Sys_UserPosts { get; set; }
        public DbSet<StrategoryModel> Sys_Strategorys { get; set; }
        public DbSet<StrategoryModuleModel> Sys_StrategoryModules { get; set; }
        public DbSet<StrategoryModuleButtonModel> Sys_StrategoryModuleButtons { get; set; }
        public DbSet<StrategoryModuleClaimModel> Sys_StrategoryModuleClaims { get; set; }
        public DbSet<StrategoryModuleButtonClaimModel> Sys_StrategoryModuleButtonClaims { get; set; }

        public DbSet<StrategoryRoleModel> Sys_StrategoryRoles { get; set; }

        public DbSet<AttachmentModel> Sys_Attachments { get; set; }
        public DbSet<AttachmentQuoteModel> Sys_AttachmentQuotes { get; set; }

        public DbSet<ScheduleModel> Quartz_Schedules { get; set; }

        public DbSet<ScheduleLogModel> Quartz_ScheduleLogs { get; set; }

        public DbSet<VersionLogModel> Sys_VersionLogs { get; set; }

        public void UpdateModel<TEntity>(TEntity model) where TEntity : class
        {
            
            Set<TEntity>().Attach(model);
            PropertyInfo[] props = model.GetType().GetProperties();
            foreach (PropertyInfo prop in props)
            {
                //var isFinal = prop.GetMethod.IsVirtual;

                if (prop.Name.ToUpper() != "ID" )
                {
                    if (prop.GetValue(model, null) != null)
                    {
                        if (prop.GetValue(model, null).ToString() == "&nbsp;")
                            Entry(model).Property(prop.Name).CurrentValue = null;
                        Entry(model).Property(prop.Name).IsModified = true;
                    }
                }

            }

        }

        public IQueryable<TEntity> IQueryable<TEntity>() where TEntity : class
        {
            return Set<TEntity>();
        }

        public IQueryable<TEntity> IQueryable<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class
        {
            return Set<TEntity>().Where(predicate);
        }

        public IList<TEntity> FindList<TEntity>(Pagination pagination) where TEntity : class
        {
            bool isAsc = pagination.sord.ToLower() == "asc" ? true : false;
            string[] _order = pagination.sidx.Split(',');
            MethodCallExpression resultExp = null;
            var tempData = Set<TEntity>().AsQueryable();
            foreach (string item in _order)
            {
                string _orderPart = item;
                _orderPart = Regex.Replace(_orderPart, @"\s+", " ");
                string[] _orderArry = _orderPart.Split(' ');
                string _orderField = _orderArry[0];
                bool sort = isAsc;
                if (_orderArry.Length == 2)
                {
                    isAsc = _orderArry[1].ToUpper() == "ASC" ? true : false;
                }
                var parameter = Expression.Parameter(typeof(TEntity), "t");
                var property = typeof(TEntity).GetProperty(_orderField);
                var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                var orderByExp = Expression.Lambda(propertyAccess, parameter);
                resultExp = Expression.Call(typeof(Queryable), isAsc ? "OrderBy" : "OrderByDescending", new Type[] { typeof(TEntity), property.PropertyType }, tempData.Expression, Expression.Quote(orderByExp));
            }

            tempData = tempData.Provider.CreateQuery<TEntity>(resultExp);
            pagination.records = tempData.Count();
            tempData = tempData.Skip<TEntity>(pagination.rows * (pagination.page - 1)).Take<TEntity>(pagination.rows).AsQueryable();
            return tempData.ToList();
        }

        public IList<TEntity> FindList<TEntity>(Expression<Func<TEntity, bool>> predicate, Pagination pagination) where TEntity : class
        {

            var tempData = FindQueryable<TEntity>(predicate, pagination);
            return tempData.ToList();
        }

        public IQueryable<TEntity> FindQueryable<TEntity>(Expression<Func<TEntity, bool>> predicate, Pagination pagination) where TEntity : class
        {

            bool isAsc = pagination.sord.ToLower() == "asc" ? true : false;
            MethodCallExpression resultExp = null;
            var tempData = Set<TEntity>().Where(predicate);
            if (!string.IsNullOrEmpty(pagination.sidx))
            {
                string[] _order = pagination.sidx.Split(',');
                foreach (string item in _order)
                {
                    string _orderPart = item;
                    _orderPart = Regex.Replace(_orderPart, @"\s+", " ");
                    string[] _orderArry = _orderPart.Split(' ');
                    string _orderField = _orderArry[0];
                    bool sort = isAsc;
                    if (_orderArry.Length == 2)
                    {
                        isAsc = _orderArry[1].ToUpper() == "ASC" ? true : false;
                    }
                    var parameter = Expression.Parameter(typeof(TEntity), "t");
                    var property = typeof(TEntity).GetProperty(_orderField);
                    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                    var orderByExp = Expression.Lambda(propertyAccess, parameter);
                    resultExp = Expression.Call(typeof(Queryable), isAsc ? "OrderBy" : "OrderByDescending", new Type[] { typeof(TEntity), property.PropertyType }, tempData.Expression, Expression.Quote(orderByExp));
                }
                tempData = tempData.Provider.CreateQuery<TEntity>(resultExp);
            }
            pagination.records = tempData.Count();
            tempData = tempData.Skip<TEntity>(pagination.rows * (pagination.page - 1)).Take<TEntity>(pagination.rows).AsQueryable();
            return tempData;
        }
    }
}
